package router

import (
	"cloud-entropy-storage-system/assets"
	"cloud-entropy-storage-system/common/pb/pbfiles"
	"cloud-entropy-storage-system/common/pkg/logger"
	"cloud-entropy-storage-system/common/pkg/session"
	"cloud-entropy-storage-system/server/internal/config"
	"cloud-entropy-storage-system/server/internal/core/server"
	"cloud-entropy-storage-system/server/model"
	"cloud-entropy-storage-system/server/model/metadata"
	"cloud-entropy-storage-system/server/model/user"
	"fmt"
	"html/template"
	"net"
	"net/http"
	"time"

	"github.com/bluele/gcache"

	"github.com/asdine/storm/v3"
	"github.com/cilidm/toolbox/rand"
	"github.com/cilidm/toolbox/str"
	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"go.uber.org/zap"
	"google.golang.org/grpc"
)

type Server struct {
	cfg     config.Config
	manager *server.Manager
	meta    *metadata.MetaData
	db      *storm.DB
	gc      gcache.Cache
	Log     *zap.Logger
	Engine  *gin.Engine
}

// NewServer 启动顺序请勿打乱
func NewServer(cfg config.Config) *Server {
	s := new(Server)
	s.cfg = cfg
	s.Log = logger.New(cfg.Log.Dir, cfg.Log.ServerName) // 1. 初始化log
	s.initDB()                                          // 2. 初始化db
	go s.startRpcServer()                               // 3. 初始化rpc服务
	s.gc = gcache.New(10000).LRU().Build()              // 4. 初始化gcache
	s.setRouter()                                       // 5. 初始化router
	return s
}

func (s *Server) initDB() {
	db, err := model.NewDB(s.cfg.Metadata.Dir)
	if err != nil {
		s.Log.Fatal("NewDB err", zap.Error(err))
	}
	m := metadata.NewMetaData(db)
	if m == nil {
		s.Log.Fatal("NewMetaData err", zap.Error(err))
	}

	s.db = db
	s.meta = m
	s.manager = server.NewServer()
	s.manager.ShowList = s.cfg.ShowVolumeList
	s.migrate()
}

func (s *Server) migrate() {
	num, err := s.db.Count(&user.User{})
	if err != nil {
		s.Log.Fatal("db count err", zap.Error(err))
	}
	if num == 0 {
		salt := rand.String(8)
		pwd := str.Md5([]byte("1234567890" + salt))
		userIns := user.User{
			Username:      "hahax",
			Password:      pwd,
			Salt:          salt,
			Status:        1,
			Nickname:      "hahax",
			Level:         99,
			LastLoginTime: time.Now(),
			CreatedAt:     time.Now(),
			UpdatedAt:     time.Now(),
		}
		err = s.db.Save(&userIns)
		if err != nil {
			s.Log.Fatal("migrate err", zap.Error(err))
		}
	}
}

func (s *Server) setRouter() {
	s.Engine = gin.Default()

	s.pprofOpen()
	s.metricsOpen()

	s.useSession()  // 开启session
	s.setFs()       // css,js文件
	s.setTemplate() // html模版

	setApi(s)
	setRender(s)
}

func (s *Server) setFs() {
	s.Engine.StaticFS("assets", http.FS(assets.Bootstrap))
}

func (s *Server) setTemplate() {
	s.Engine.SetHTMLTemplate(template.Must(template.New("").ParseFS(assets.Templates, "templates/*")))
}

func (s *Server) useSession() {
	s.Engine.Use(session.EnableCookieSession(session.NewCookieSessionReq().
		SetSessionName("_GOFILE_Session").SetMaxAge(7 * 24 * 3600)))
}

func (s *Server) pprofOpen() {
	pprof.Register(s.Engine)
}

func (s *Server) metricsOpen() {
	s.Engine.GET("/metrics", gin.WrapH(promhttp.Handler()))
}

func (s *Server) startRpcServer() {
	lis, err := net.Listen("tcp",
		fmt.Sprintf("%s:%d", s.cfg.RpcServer.Host, s.cfg.RpcServer.Port))
	if err != nil {
		s.Log.Fatal("failed to listen", zap.Error(err))
	}

	var options = []grpc.ServerOption{
		grpc.MaxRecvMsgSize(s.cfg.Rpc.MaxRecvMsgSize),
		grpc.MaxSendMsgSize(s.cfg.Rpc.MaxSendMsgSize),
	}
	grpcServer := grpc.NewServer(options...)
	heartService := server.NewVolumesHeart()
	pbfiles.RegisterVolumeHeartServer(grpcServer, heartService)
	if err = grpcServer.Serve(lis); err != nil {
		s.Log.Fatal("启动失败", zap.Error(err))
	}
}

func (s *Server) Close() {
	if err := s.db.Close(); err != nil {
		s.Log.Error(err.Error())
	}
}
